﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using theeg.GeometryWpf;
using theeg.GraphWpf.Arrangement;

namespace theeg.GraphWpf.Models
{
    public class Transition : NotifyingObject, IHilbertTreeNode
    {
        public int GenericInt;
        private ComputationalRectangle _boundingBox;
        internal List<Point> RoutingPoints { get; private set; }
        public ConnectorOrientation SourceOrientation { get; set; }
        public ConnectorOrientation TargetOrientation { get; set; }

        private bool _isHighlighted;
        public bool IsHighlighted
        {
            get { return _isHighlighted; }
            set
            {
                if (value != _isHighlighted)
                {
                    _isHighlighted = value;
                    RaisePropertyChanged("IsHighlighted");
                }
            }
        }

        private double _magnitude = 1.0;
        public double Magnitude
        {
            get { return _magnitude; }
            set
            {
                if (!Equals(value, _magnitude))
                {
                    _magnitude = value;
                    RaisePropertyChanged("Source");
                }
            }
        }

        private Brush _brush = new SolidColorBrush(Colors.Black);
        public Brush Brush
        {
            get { return _brush; }
            set
            {
                if (!Equals(value, _brush))
                {
                    _brush = value;
                    RaisePropertyChanged("Brush");
                }
            }
        }

        private readonly IList<Point> _controlPoints = new List<Point>();
        public IEnumerable<Point> ControlPoints
        {
            get
            {
                return _controlPoints;
            }
        }

        public RoutingStyle RoutingStyle { get; set; }

        public Transition()
        {
            RoutingPoints = new List<Point>();
            TargetCapital = TransitionCapital.Arrow;
            RoutingStyle = RoutingStyle.TwoPointVertical;
        }

        public int Category { get { return 1; } }

        public double CenterX
        {
            get
            {
                if (_boundingBox == null) GetBoundingBox();
                return (_boundingBox.L + _boundingBox.R) * 0.5;
            }
        }

        public double CenterY
        {
            get
            {
                if (_boundingBox == null) GetBoundingBox();
                return (_boundingBox.L + _boundingBox.R) * 0.5;
            }
        }

        private string _sourceText;
        public string SourceText
        {
            get { return _sourceText; }
            set
            {
                if (!Equals(value, _sourceText))
                {
                    _sourceText = value;
                    RaisePropertyChanged("SourceText");
                }
            }
        }

        private string _targetText;
        public string TargetText
        {
            get { return _targetText; }
            set
            {
                if (!Equals(value, _targetText))
                {
                    _targetText = value;
                    RaisePropertyChanged("TargetText");
                }
            }
        }

        public ComputationalRectangle GetBoundingBox()
        {
            if (_boundingBox == null)
            {
                double minX, maxX, minY, maxY;
                minX = Math.Min(Source.Left, Target.Left);
                maxX = Math.Max(Source.Left, Target.Left);
                minY = Math.Min(Source.Top, Target.Top);
                maxY = Math.Max(Source.Top, Target.Top);
                foreach (var controlPoint in _controlPoints)
                {
                    minX = Math.Min(minX, controlPoint.X);
                    maxX = Math.Max(maxX, controlPoint.X);
                    minY = Math.Min(minY, controlPoint.Y);
                    maxY = Math.Max(maxY, controlPoint.Y);
                }
                _boundingBox = new ComputationalRectangle(minX, minY, maxX, maxY);
            }
            return _boundingBox;
        }

        public ShapeOverlapping Contains(ComputationalShape range)
        {
            if (_boundingBox == null) GetBoundingBox();
            return range.Contains(_boundingBox);
        }

        public double GetDistanceFrom(Point pt)
        {
            throw new NotImplementedException();
        }

        public double GetLevelOfDetailFactor()
        {
            throw new NotImplementedException();
        }

        public void SetConnection(INode source, INode target)
        {
            if (Source != null && Source.OutgoingEdges.Contains(this))
            {
                Source.OutgoingEdges.Remove(this);
            }
            if (Target != null && Target.IncomingEdges.Contains(this))
            {
                Target.IncomingEdges.Remove(this);
            }
            Source = source;
            Target = target;
            if (!Source.OutgoingEdges.Contains(this))
            {
                Source.OutgoingEdges.Add(this);
            }
            if (!Target.IncomingEdges.Contains(this))
            {
                Target.IncomingEdges.Add(this);
            }
        }

        private INode _source;

        public INode Source
        {
            get { return _source; }
            private set
            {
                if (value != _source)
                {
                    _source = value;
                    RaisePropertyChanged("Source");
                }
            }
        }

        private INode _target;
        public INode Target
        {
            get { return _target; }
            private set
            {
                if (value != _target)
                {
                    _target = value;
                    RaisePropertyChanged("Target");
                }
            }
        }

        private TransitionCapital _sourceCapital;
        public TransitionCapital SourceCapital
        {
            get { return _sourceCapital; }
            set
            {
                if (value != _sourceCapital)
                {
                    _sourceCapital = value;
                    RaisePropertyChanged("SourceCapital");
                }
            }
        }

        private TransitionCapital _targetCapital;
        public TransitionCapital TargetCapital
        {
            get { return _targetCapital; }
            set
            {
                if (value != _targetCapital)
                {
                    _targetCapital = value;
                    RaisePropertyChanged("TargetCapital");
                }
            }
        }

        private Visibility _visibility;
        public Visibility Visibility
        {
            get { return _visibility; }
            set
            {
                if (value != _visibility)
                {
                    _visibility = value;
                    RaisePropertyChanged("Visibility");
                }
            }
        }

        private TransitionStyle _transitionStyle;

        public TransitionStyle TransitionStyle
        {
            get { return _transitionStyle; }
            set
            {
                if (value != _transitionStyle)
                {
                    _transitionStyle = value;
                    RaisePropertyChanged("TransitionStyle");
                }
            }
        }

        public void ClearControlPoints()
        {
            _controlPoints.Clear();
            _boundingBox = null;
        }

        public void RemoveControlPoint(int index)
        {
            _controlPoints.RemoveAt(index);
            _boundingBox = null;
        }

        public void AddControlPoint(Point point)
        {
            _controlPoints.Add(point);
            _boundingBox = null;
        }
    }
}